A Simple Geometry library for OpenGL |
by Steve Baker |
SG is now a part of PLIB.
Since SG is designed to work with OpenGL, it uses similar naming conventions - all SG functions and other tokens that work with 'float' precision math begin with 'sg' or 'SG'. There are a complete duplicate set that work with double-precision math that begin with 'sgd' or 'SGD'.
Most SG functions are implemented as 'inline' C++ functions - for speed. The underlying data types are mostly just arrays of 'float' - which is generally the most efficient type for OpenGL programs.
SGD functions are absolutely identical to their SG eqivelents - except for working at double precision. This document doesn't describe the SGD functions, types and constants. That would just be a waste of space - they are just identical to the SG versions.
SGfloat -- A floating point number. sgVec2 -- A two element array of SGfloat sgVec3 -- A three element array of SGfloat sgVec4 -- A four element array of SGfloat sgMat4 -- A 4x4 element array of SGfloat sgCoord -- A simple structure used to hold euler rotation angles and a 3D translation: struct sgCoord { sgVec3 xyz ; sgVec3 hpr ; } ; sgLine3 -- An infinite line defined by a point somewhere on the line and a normalized direction vector. struct sgLine3 { sgVec3 point_on_line ; sgVec3 direction_vector ; /* Should be a unit vector */ } ; sgLineSegment3 -- A finite line segment defined by it's end-points. struct sgLineSegment3 { sgVec3 a ; sgVec3 b ; } ; sgQuat -- An sgVec4 holding the values (x, y, z, w), representing the quaternion w + xi + yj + zk. class sgSphere -- A sphere class sgBox -- An axially aligned box. class sgFrustum -- An OpenGL-style view frustum ...and the same again but in 'double' precision: SGDfloat, sgdVec2, sgdVec3, sgdVec4, sgdMat4, sgdCoord, sgdQuat, sgdSphere, sgdBox, sgdFrustumNote 1: All angles used by or produced by SG are in degrees.
Note 2: Some functions refer to 'angle+axis' notation for rotations, this is the same format that glRotate uses.
SG calls the first form a "line segment" (sgLineSegment3) and the second form an "infinite line" (sgLine3).
You can find the infinite line that is the extension of a line segment using:
void sgLineSegment3ToLine3 ( sgLine3 *line, const sgLineSegment3 lineseg ) ;You can also find the distance from a point to either a line or a line segment using:
SGfloat sgDistToLineVec3 ( const sgLine3 line, const sgVec3 pnt ) SGfloat sgDistToLineSegmentVec3 ( const sgLineSegment3 line, const sgVec3 pnt ) SGfloat sgDistSquaredToLineVec3 ( const sgLine3 line, const sgVec3 pnt ) ; SGfloat sgDistSquaredToLineSegmentVec3 ( const sgLineSegment3 line, const sgVec3 pnt ) ;Try to use the 'Squared' versions if you can because you save a costly sqrt() function.
sgMat4 m ; sgMakeIdentMat4 ( m ) ; glLoadMatrixf ( (GMfloat *) m ) ; ...or... sgdMat4 m ; sgdMakeIdentMat4 ( m ) ; glLoadMatrixd ( (GMdouble *) m ) ;Another way to look at this is to treat an sgMat4 as an array of four sgVec4's. This is convenient for quite a few reasons. For example, you can extract the sgVec3 that represents the translation part of an sgMat4 by just using mat[3] anywhere where an sgMat3 would be appropriate.
NOTES:
|
|
Hence (in the ASS case), SG needs to know whether one of the unknown vertices is greater than 90 degrees (Obtuse) or less than 90 degrees (Acute). Hence the two routines below that use ASS notation have to be told whether angA is Obtuse or not.
void sgTriangleSolver_SSStoAAA ( SGfloat lenA, SGfloat lenB, SGfloat lenC, SGfloat *angA, SGfloat *angB, SGfloat *angC ) ; void sgTriangleSolver_SAStoASA ( SGfloat lenA, SGfloat angB, SGfloat lenC, SGfloat *angA, SGfloat *lenB, SGfloat *angC ) ; void sgTriangleSolver_ASAtoSAS ( SGfloat angA, SGfloat lenB, SGfloat angC, SGfloat *lenA, SGfloat *angB, SGfloat *lenC ) ; void sgTriangleSolver_SAAtoASS ( SGfloat lenA, SGfloat angB, SGfloat angA, SGfloat *angC, SGfloat *lenB, SGfloat *lenC ) ; void sgTriangleSolver_ASStoSAA ( SGfloat angB, SGfloat lenA, SGfloat lenB, bool angA_is_obtuse, SGfloat *lenC, SGfloat *angA, SGfloat *angC ) ;These functions take three parameters which are a mixture of lengths and angles for an arbitary triangle. They return the missing three parameters. In all cases of 'degenerate' triangles (eg zero angles, zero lengths), the package comes up with a plausible result - although it may not be a unique solution. This should be robust and more roundoff-error-tolerant than producing an error return.
Impossible triangles will produce all-zero results.
If one or more of the results are not needed, pass a NULL pointer for it and the package can avoid doing the unnecessary trig and perhaps run a little faster.
SGfloat sgTriangleSolver_ASAtoArea ( SGfloat angA, SGfloat lenB, SGfloat angC ) ; SGfloat sgTriangleSolver_SAStoArea ( SGfloat lenA, SGfloat angB, SGfloat lenC ) ; SGfloat sgTriangleSolver_SSStoArea ( SGfloat lenA, SGfloat lenB, SGfloat lenC ) ; SGfloat sgTriangleSolver_SAAtoArea ( SGfloat lenA, SGfloat angB, SGfloat angA ) ; SGfloat sgTriangleSolver_ASStoArea ( SGfloat angB, SGfloat lenA, SGfloat lenB, bool angA_is_obtuse ) ;These compute the area of a triangle from three parameters. Impossible triangles (eg lenA > lenB+lenC) return zero areas.
There is a rich set of functions to interconvert sgCoord's and sgMat4's.
It can be used to encode rotations. The quaternion (sin(a) * v, cos(a)) rotates 2*a about the vector v.
There is a rich set of functions to interconvert sgQuat's and other rotation structures.
class sgSphere { public: sgVec3 center ; SGfloat radius ; SGfloat *getCenter (void) ; SGfloat getRadius (void) ; void setCenter ( SGfloat x, SGfloat y, SGfloat z ) ; void setRadius ( SGfloat r ) ; int isEmpty (void) ; void empty (void) ; void orthoXform ( sgMat4 m ) ; void extend ( sgSphere *s ) ; void extend ( sgBox *b ) ; void extend ( sgVec3 v ) ; int intersects ( sgSphere *s ) ; int intersects ( sgVec4 plane ) ; int intersects ( sgBox *b ) ; } ;Since sgSphere's are frequently used as simple bounding shapes for field-of-view culling, it's quite useful to be able to represent an 'empty' sphere. This is represented using a sphere of Negative radius.
The 'isEmpty()' function tests to see if a sphere is empty and the 'empty()' function forces the sphere to be empty.
The 'orthoXform(m)' function transforms the sphere using the matrix 'm' - which must be orthographic (since transforming a sphere by a non-ortho matrix yields something that's no longer spherical).
Three 'extend' functions allow you to expand the sphere to encompass other shapes. These functions attempt to minimise the radius of the resulting sphere:
void extend ( sgSphere *s ) ; void extend ( sgBox *b ) ; void extend ( sgVec3 v ) ;There are also three intersection tests that return TRUE if the volume contained by the sphere intersects the volume contained by the other object:
int intersects ( sgSphere *s ) ; int intersects ( sgBox *b ) ; int intersects ( sgVec4 plane ) ;('plane' in this context means the semi-infinite volume bounded by that plane).
class sgBox { public: sgVec3 min ; sgVec3 max ; SGfloat *getMin (void) ; SGfloat *getMax (void) ; void setMin ( SGfloat x, SGfloat y, SGfloat z ) ; void setMax ( SGfloat x, SGfloat y, SGfloat z ) ; int isEmpty(void) ; void empty (void) ; void extend ( sgSphere *s ) ; void extend ( sgBox *b ) ; void extend ( sgVec3 v ) ; int intersects ( sgSphere *s ) ; int intersects ( sgBox *b ) ; int intersects ( sgVec4 plane ) ; } ;Since sgBox'es are frequently used as simple bounding shapes for field-of-view culling, it's quite useful to be able to represent an 'empty' box. This is represented using a box whose minumum vertex has larger X, Y or Z than its maximum vertex.
The 'isEmpty()' function tests to see if a box is empty and the 'empty()' function forces the box to be empty.
Three 'extend' functions allow you to expand the box to encompass other shapes. These functions attempt to minimise the size of the resulting box:
void extend ( sgSphere *s ) ; void extend ( sgBox *b ) ; void extend ( sgVec3 v ) ;There are also three intersection tests that return TRUE if the volume contained by the box intersects the volume contained by the other object:
int intersects ( sgSphere *s ) ; int intersects ( sgBox *b ) ; int intersects ( sgVec4 plane ) ;('plane' in this context means the semi-infinite volume bounded by that plane).
class sgFrustum { public: sgFrustum (void) ; void setFrustum ( SGfloat left , SGfloat right, SGfloat bottom, SGfloat top, SGfloat near , SGfloat far ) ; void setFOV ( SGfloat h, SGfloat v ) ; void setNearFar ( SGfloat n, SGfloat f ) ; SGfloat getHFOV (void) ; SGfloat getVFOV (void) ; SGfloat getNear (void) ; SGfloat getFar (void) ; SGfloat getLeft (void) ; SGfloat getRight(void) ; SGfloat getTop (void) ; SGfloat getBot (void) ; void getFOV ( SGfloat *h, SGfloat *v ) ; void getNearFar ( SGfloat *n, SGfloat *f ) ; int contains ( sgVec3 p ) ; int contains ( sgSphere *s ) ; } ;There are two ways to use an sgFrustum:
int contains ( sgVec3 p ) ; int contains ( sgSphere *s ) ;...returns SG_OUTSIDE if the point or sphere lies entirely outside the volume contained by the frustum, SG_INSIDE if it lies entirely inside the frustum - or SG_STRADDLE if they only partially overlap.
#define SG_PI #define SG_DEGREES_TO_RADIANS #define SG_RADIANS_TO_DEGREES
sgAddVec3 ( dst, a, b ) ; /* dst = a + b ; */ sgAddVec3 ( dst, a ) ; /* dst += a ; */The following functions exist:
void sgZeroVec2 ( sgVec2 dst ) ; void sgZeroVec3 ( sgVec3 dst ) ; void sgZeroVec4 ( sgVec4 dst ) ; void sgSetVec2 ( sgVec2 dst, SGfloat x, SGfloat y ) ; void sgSetVec3 ( sgVec3 dst, SGfloat x, SGfloat y, SGfloat z ) ; void sgSetVec4 ( sgVec4 dst, SGfloat x, SGfloat y, SGfloat z, SGfloat w ) ; void sgCopyVec2 ( sgVec2 dst, sgVec2 src ) void sgCopyVec3 ( sgVec3 dst, sgVec3 src ) void sgCopyVec4 ( sgVec4 dst, sgVec4 src ) void sgAddVec2 ( sgVec2 dst, sgVec2 src ) void sgAddVec3 ( sgVec3 dst, sgVec3 src ) void sgAddVec4 ( sgVec4 dst, sgVec4 src ) void sgAddVec2 ( sgVec2 dst, sgVec2 src1, sgVec2 src2 ) void sgAddVec3 ( sgVec3 dst, sgVec3 src1, sgVec3 src2 ) void sgAddVec4 ( sgVec4 dst, sgVec4 src1, sgVec4 src2 ) void sgSubVec2 ( sgVec2 dst, sgVec2 src ) void sgSubVec3 ( sgVec3 dst, sgVec3 src ) void sgSubVec4 ( sgVec4 dst, sgVec4 src ) void sgSubVec2 ( sgVec2 dst, sgVec2 src1, sgVec2 src2 ) void sgSubVec3 ( sgVec3 dst, sgVec3 src1, sgVec3 src2 ) void sgSubVec4 ( sgVec4 dst, sgVec4 src1, sgVec4 src2 ) void sgNegateVec2 ( sgVec2 dst ) void sgNegateVec3 ( sgVec3 dst ) void sgNegateVec4 ( sgVec4 dst ) void sgNegateVec2 ( sgVec2 dst, sgVec2 src ) void sgNegateVec3 ( sgVec3 dst, sgVec3 src ) void sgNegateVec4 ( sgVec4 dst, sgVec4 src ) void sgScaleVec2 ( sgVec2 dst, SGfloat s ) void sgScaleVec3 ( sgVec3 dst, SGfloat s ) void sgScaleVec4 ( sgVec4 dst, SGfloat s ) void sgScaleVec2 ( sgVec2 dst, sgVec2 src, SGfloat s ) void sgScaleVec3 ( sgVec3 dst, sgVec3 src, SGfloat s ) void sgScaleVec4 ( sgVec4 dst, sgVec4 src, SGfloat s ) void sgAddScaledVec2 ( sgVec2 dst, svVec2 src, SGfloat s ) void sgAddScaledVec3 ( sgVec3 dst, svVec3 src, SGfloat s ) void sgAddScaledVec4 ( sgVec4 dst, svVec4 src, SGfloat s ) void sgAddScaledVec2 ( sgVec2 dst, sgVec2 a, svVec2 b, SGfloat s ) void sgAddScaledVec3 ( sgVec3 dst, sgVec3 a, svVec3 b, SGfloat s ) void sgAddScaledVec4 ( sgVec4 dst, sgVec4 a, svVec4 b, SGfloat s ) int sgCompareVec2 ( sgVec2 a, sgVec2 b, SGfloat tol ) int sgCompareVec3 ( sgVec3 a, sgVec3 b, SGfloat tol ) int sgCompareVec4 ( sgVec4 a, sgVec4 b, SGfloat tol ) int sgEqualVec2 ( sgVec2 a, sgVec2 b ) int sgEqualVec3 ( sgVec3 a, sgVec3 b ) int sgEqualVec4 ( sgVec4 a, sgVec4 b ) SGfloat sgScalarProductVec2 ( sgVec2 a, sgVec2 b ) SGfloat sgScalarProductVec3 ( sgVec3 a, sgVec3 b ) SGfloat sgScalarProductVec4 ( sgVec4 a, sgVec4 b ) void sgVectorProductVec3 ( sgVec3 dst, sgVec3 a, sgVec3 b ) SGfloat sgLerp ( SGfloat a, SGfloat b, SGfloat f ) void sgLerp2 ( sgVec2 dst, sgVec2 a, sgVec2 b, SGfloat f ) void sgLerp3 ( sgVec3 dst, sgVec3 a, sgVec3 b, SGfloat f ) void sgLerp4 ( sgVec4 dst, sgVec4 a, sgVec4 b, SGfloat f ) SGfloat sgDistanceSquaredVec2 ( sgVec2 a, sgVec2 b ) SGfloat sgDistanceSquaredVec3 ( sgVec3 a, sgVec3 b ) SGfloat sgDistanceSquaredVec4 ( sgVec4 a, sgVec4 b ) SGfloat sgDistanceVec2 ( sgVec2 a, sgVec2 b ) SGfloat sgDistanceVec3 ( sgVec3 a, sgVec3 b ) SGfloat sgDistanceVec4 ( sgVec4 a, sgVec4 b ) SGfloat sgLengthVec2 ( sgVec2 src ) SGfloat sgLengthVec3 ( sgVec3 src ) SGfloat sgLengthVec4 ( sgVec4 src ) /* Anglo-US spelling issues. <sigh> */ #define sgNormalizeVec2 sgNormaliseVec2 #define sgNormalizeVec3 sgNormaliseVec3 #define sgNormalizeVec4 sgNormaliseVec4 void sgNormaliseVec2 ( sgVec2 dst ) void sgNormaliseVec3 ( sgVec3 dst ) void sgNormaliseVec4 ( sgVec4 dst ) void sgNormaliseVec2 ( sgVec2 dst, sgVec2 src ) void sgNormaliseVec3 ( sgVec3 dst, sgVec3 src ) void sgNormaliseVec4 ( sgVec4 dst, sgVec4 src )
void sgCopyMat4 ( sgMat4 dst, sgMat4 src ) ; void sgMakeIdentMat4 ( sgMat4 dst ) ; void sgMakeCoordMat4 ( sgMat4 dst, SGfloat x, SGfloat y, SGfloat z, SGfloat h, SGfloat p, SGfloat r ) ; void sgMakeCoordMat4 ( sgMat4 dst, sgVec3 xyz, sgVec3 hpr ) void sgMakeCoordMat4 ( sgMat4 dst, sgCoord *src ) void sgMakeRotMat4 ( sgMat4 dst, sgVec3 hpr ) void sgMakeRotMat4 ( sgMat4 dst, SGfloat h, SGfloat p, SGfloat r ) void sgMakeRotMat4 ( sgMat4 dst, SGfloat angle, sgVec3 axis ) ; void sgMakeTransMat4 ( sgMat4 dst, sgVec3 xyz ) ; void sgMakeTransMat4 ( sgMat4 dst, SGfloat x, SGfloat y, SGfloat z ) ; void sgQuatToMatrix ( sgMat4 dst, sgQuat quat ) ;You can multiply matrices:
void sgMultMat4 ( sgMat4 dst, sgMat4 a, sgMat4 b ) ; void sgPostMultMat4 ( sgMat4 dst, sgMat4 a ) ; void sgPreMultMat4 ( sgMat4 dst, sgMat4 a ) ;You can do a cheap matrix inversion (for simple rotate/translate matrices):
void sgTransposeNegateMat4 ( sgMat4 dst ) ; void sgTransposeNegateMat4 ( sgMat4 dst, sgMat4 src ) ;...or a (more costly) full matrix inversion (for more complex matrices):
void sgInvertMat4 ( sgMat4 dst ) ; void sgInvertMat4 ( sgMat4 dst, sgMat4 src ) ;You can transform vertices and points using a matrix. The 'Vec*' forms assume that the vector merely need to be rotated (like you would want for a surface normal for example) - whilst the 'Pnt*' forms perform a rotate and translate. If your matrix is more complex and contains scaling, shearing, perspective and such like, then use the 'FullXform' versions - which are quite a bit slower than the other forms:
void sgXformVec3 ( sgVec3 dst, sgMat4 mat ) ; void sgXformVec3 ( sgVec3 dst, sgVec3 src, sgMat4 mat ) ; void sgXformPnt3 ( sgVec3 dst, sgMat4 mat ) ; void sgXformPnt3 ( sgVec3 dst, sgVec3 src, sgMat4 mat ) ; void sgFullXformPnt3 ( sgVec3 dst, sgMat4 mat ) ; void sgFullXformPnt3 ( sgVec3 dst, sgVec3 src, sgMat4 mat ) ; void sgXformVec4 ( sgVec4 dst, sgMat4 mat ) ; void sgXformVec4 ( sgVec4 dst, sgVec4 src, sgMat4 mat ) ; void sgXformPnt4 ( sgVec4 dst, sgMat4 mat ) ; void sgXformPnt4 ( sgVec4 dst, sgVec4 src, sgMat4 mat ) ; void sgFullXformPnt4 ( sgVec4 dst, sgMat4 mat ) ; void sgFullXformPnt4 ( sgVec4 dst, sgVec4 src, sgMat4 mat ) ;The properties of a matrix can be tested with:
int sgClassifyMat4 ( const sgMat4 mat ) ;which returns a bitmask with zero or more of the following bits set:
SG_ROTATION | Upper 3x3 includes a rotational component. |
SG_MIRROR | Changes handedness. |
SG_SCALE | Uniform scaling going on. |
SG_NONORTHO | Upper 3x3 not orthogonal (including non-uniform scaling). |
SG_TRANSLATION | Translates. |
SG_PROJECTION | Fourth column not 0,0,0,1. |
void sgZeroCoord ( sgCoord *dst ) ; void sgSetCoord ( sgCoord *dst, SGfloat x, SGfloat y, SGfloat z, SGfloat h, SGfloat p, SGfloat r ) ; void sgSetCoord ( sgCoord *dst, sgVec3 xyz, sgVec3 hpr ) ; void sgSetCoord ( sgCoord *coord, sgMat4 src ) ; void sgCopyCoord ( sgCoord *dst, sgCoord *src ) ;The varient of sgSetCoord that takes a matrix is somewhat tricky since there is no way to convert matrices that are not simple rotate/translates into sgCoord's - and even when the matrix is a simple rotate/translate, there are a number of possible sets of Euler rotations that could be appropriate to reproduce the behavior of the input matrix. sgSetCoord picks a valid rotation - but just beware of this behaviour.
void sgMakeIdentQuat ( sgQuat dst ) ;Creates the identity quaternion. (0,0,0,1)
void sgSetQuat ( sgQuat dst, SGfloat w, SGfloat x, SGfloat y, SGfloat z ) ;Sets the four components of the quaternion.
void sgCopyQuat ( sgQuat dst, sgQuat src ) ;Copies one quaternion into another.
void sgNormalizeQuat ( sgQuat dst ) ; void sgNormalizeQuat ( sgQuat dst, sgQuat src ) ;For most operations, quaternions need to be normalized, these functions ensure that they are.
void sgInvertQuat ( sgQuat dst ) ; void sgInvertQuat ( sgQuat dst, sgQuat src ) ;Computes the inverse of a quaternion.
void sgQuatToAngleAxis ( SGfloat *angle, sgVec3 axis, const sgQuat src ) ; void sgQuatToAngleAxis ( SGfloat *angle, SGfloat *x, SGfloat *y, SGfloat *z, const sgQuat src ) ;Converts a quaternion into an angle+axis format - just the thing to pass to glRotate for example.
void sgAngleAxisToQuat ( sgQuat dst, SGfloat angle, const sgVec3 axis ) ; void sgAngleAxisToQuat ( sgQuat dst, SGfloat angle, SGfloat x, SGfloat y, SGfloat z ) ;Converts an angle+axis rotation into a quaternion.
void sgMultQuat ( sgQuat dst, sgQuat a, sgQuat b ) ; void sgPostMultQuat ( sgQuat dst, sgQuat q ) ; void sgPreMultQuat ( sgQuat dst, sgQuat q ) ;Concatenates quaternion rotations.
void sgQuatToMatrix ( sgMat4 mat, sgQuat quat ) ; void sgMatrixToQuat ( sgQuat quat, sgMat4 mat ) ;Converts between quaternions and rotation matrices.
void sgPostRotQuat ( sgQuat dst, SGfloat angle, sgVec3 axis ) void sgPostRotQuat ( sgQuat dst, SGfloat angle, SGfloat x, SGfloat y, SGfloat z ) void sgPreRotQuat ( sgQuat dst, SGfloat angle, SGfloat x, SGfloat y, SGfloat z )Rotates a quaternion by an angle/axis rotation.
extern void sgSlerpQuat ( sgQuat dst, const sgQuat from, const sgQuat to, const SGfloat t ) ;Interpolates between two quaternions.
void sgHPRfromVec3 ( sgVec3 hpr, sgVec3 src ) ;This function takes a vector representing a direction and computes a suitable heading and pitch angle to look along that vector. Since the roll angle is indeterminate, it is set to zero.
void sgMakeNormal ( sgVec3 dst, sgVec3 a, sgVec3 b, sgVec3 c ) ;This finds the surface normal of a triangle given three vertices.
SGfloat sgDistToPlaneVec3 ( sgVec4 plane, sgVec3 pnt ) ;This returns the distance from the point to the plane.
SGfloat sgHeightAbovePlaneVec3 ( sgVec4 plane, sgVec3 pnt ) ;This returns the vertical (Z) distance from the point to the plane (my applications tend to use Z-is-up conventions).
void sgMakePlane ( sgVec4 dst, sgVec3 a, sgVec3 b, sgVec3 c ) ;This finds the plane equation of a triangle given three vertices.
void sgMakePlane ( sgVec4 dst, sgVec3 normal, sgVec3 pnt ) ;This finds the plane equation of a plane given its normal and a point on the plane.
int sgIsectPlanePlane ( sgVec3 point, sgVec3 dir, sgVec4 plane1, sgVec4 plane2 ) ;Two planes intersect along an infinite line. Given two planes, this routine routines a point and direction for the intersection line. It returns FALSE if presented with two parallel planes, TRUE otherwise.
int sgIsectInfLinePlane ( sgVec3 dst, sgVec3 l_org, sgVec3 l_vec, sgVec4 plane ) ;Given a plane, and an infinite line, this routine routines the point at which they intersect. It returns FALSE if presented with a line which is parallel to the plane, TRUE otherwise.
int sgIsectInfLineInfLine ( sgVec3 dst, sgVec3 l1_org, sgVec3 l1_vec, sgVec3 l2_org, sgVec3 l2_vec ) ;Two infinite lines in 3D are unlikely to intersect - even if you actually expect them to (because of roundoff error). Hence, this routine sets dst to the closest point on the second line which is closest to the first line. Return FALSE if the lines are parallel, TRUE otherwise.
SGfloat sgIsectLinesegPlane ( sgVec3 dst, sgVec3 v1, sgVec3 v2, sgVec4 plane ) ;Intersect a line segment with a plane. The return result is in the range 0..1 if the intersection lies between v1 and v2, >1 if beyond v2 and <0 if before v1. FLT_MAX is returned if the vector does not intersect the plane.
void sgdSetVec2 ( sgdVec2 dst, sgVec2 src ) ; void sgdSetVec3 ( sgdVec3 dst, sgVec3 src ) ; void sgdSetVec4 ( sgdVec4 dst, sgVec4 src ) ; void sgdSetMat4 ( sgdMat4 dst, sgMat4 src ) ; void sgdSetCoord ( sgdCoord *dst, sgCoord *src ) ; void sgSetVec2 ( sgVec2 dst, sgdVec2 src ) ; void sgSetVec3 ( sgVec3 dst, sgdVec3 src ) ; void sgSetVec4 ( sgVec4 dst, sgdVec4 src ) ; void sgSetMat4 ( sgMat4 dst, sgdMat4 src ) ; void sgSetCoord ( sgCoord *dst, sgdCoord *src ) ;
class sgPerlinNoise_1D { sgPerlinNoise_1D () ; void regenerate () ; SGfloat getNoise ( SGfloat x ) ; } ; class sgPerlinNoise_2D { sgPerlinNoise_2D () ; void regenerate () ; SGfloat getNoise ( sgVec2 pos ) ; SGfloat getNoise ( SGfloat x, SGfloat y ) ; } ; class sgPerlinNoise_3D { sgPerlinNoise_3D () ; void regenerate () ; SGfloat getNoise ( sgVec3 pos ) ; SGfloat getNoise ( SGfloat x, SGfloat y, SGfloat z ) ; } ;In each case, you simply construct the class, then call 'getNoise' with the coordinate (either one, two or three-dimensional) at which you need the value for the noise function. Perlin noise is both repeatable (if you make the same request twice, you get the same result) and continuous (there are no large jumps between results for points that are close to one-another).
Calling 'regenerate' will cause the function to subsequently generate a different noise pattern (presuming you didn't re-seed the 'rand()' function to the same value before each call).
class sgParticle ; class sgSpringDamper ;The idea is that you connect up a bunch of 'particles' (which each have mass, position and velocity) using a collection of springs (actually, these are combinations springs and dampers). Then, each frame, you can apply forces to some or all of the particles - and perhaps forcably reposition some of them - then loop around updating all of the spring-damper models to see what forces they apply to the particles as a result. Finally, you should call the 'upadate' function for each particle to see where it ends up some short time later.
class sgParticle { sgParticle ( float mass ) ; sgParticle ( float mass, float x, float y, float z ) ; sgParticle ( float mass, sgVec3 position ) ; float *getPos () ; float *getVel () ; float *getForce () ; float getMass () ; void setPos ( sgVec3 p ) ; void setVel ( sgVec3 v ) ; void setForce ( sgVec3 f ) ; void setPos ( float x, float y, float z ) ; void setVel ( float x, float y, float z ) ; void setForce ( float x, float y, float z ) ; void setMass ( float m ) ; void zeroForce () ; void addForce ( sgVec3 f ) ; void gravityOnly () ; void bounce ( sgVec3 normal, float coefRestitution ) ; void update ( float dt ) ; } ;Aside from the obvious set/get routines that allow you to set or get the particles mass, position, velocity and the total force that's applied to it, you can also zero the force (a usual thing to do at the start of each cycle) or set the force equal to normal gravity, or you can add a force to whatever is currently being applied. The constructor function requires that you pass in the mass and (optionally) the initial position. The mass of a particle cannot ever be zero because you'll get divide-by-zero errors all over the place if you do.
class sgSpringDamper { sgSpringDamper () ; sgSpringDamper ( sgParticle *_p0, sgParticle *_p1, float _stiffness, float _damping, float _restLength = -1.0f ) ; float getRestLength () ; float getStiffness () ; float getDamping () ; sgParticle *getParticle ( int which ) ; void setParticles ( sgParticle *_p0, sgParticle *_p1 ) ; void setParticle ( int which, sgParticle *p ) ; void setRestLength () ; void setRestLength ( float l ) ; void setStiffness ( float s ) ; void setDamping ( float d ) ; void update () ; } ;Each spring/damper is connected to two sgParticle's. It has a stiffness and a damping factor plus a 'rest' length (ie how long it is when no forces are applied to the system). If you omit the rest length, it will be calculated from the current positions of the two particles.
Apart from the usual set/get functions, there is a single 'update' routine which calculates the forces on the two particles and calls 'addForce' to each.
A typical application will look like this:
Initialisation:
particle->zeroForce () ;
...or...
particle->gravityOnly () ;
...or...
particle->setForce ( something ) ;
spring -> update () ;
particle -> update ( dt )
(where 'dt' is the elapsed time since the previous frame).
sgParticle::bounce ( sgVec3 normal, float coefRestitution )
(Where 'normal' is the surface normal of the plane we hit and
'coefRestitution' is 1.0 for perfectly elastic surfaces, 0.0 for
ultra-sticky surfaces...or somewhere in between).
You have been warned!
By default, gravity is set to -9.8 meters/sec/sec in the Z direction - but this assumes you are on earth, using the metric (mks) system and have Z-is-up coordinates.
If any of those are not true, you can change the force that 'particle->gravityOnly()' applies using:
void sgSetGravity ( float g ) ; void sgSetGravityVec3 ( sgVec3 g ) ; float *sgGetGravityVec3 () ; float sgGetGravity () ;Note that 'sgSetGravity' and 'sgGetGravity' use positive numbers for the accelleration due to gravity - and assume Z-is-up. But the 'Vec3' versions make neither of those assumptions - so make sure the vector you give points DOWNWARDS!
eg
sgSetGravity ( 1.6 ) ; /* On the Moon! */...but...
sgSetVec3 ( lunar_gravity, 0.0, 0.0, -1.6 ) ; /* Note minus sign! */ sgSetGravityVec3 ( lunar_gravity ) ;
Steve J. Baker. <sjbaker1@airmail.net> |